package worker

import (
	"crontab/common"
	"math/rand"
	"os/exec"
	"strings"
	"time"
)

type Executor struct {

}


// 执行一个任务
func (e *Executor) ExecutorJob(info *common.JobExecuteInfo) {

	go func() {
		var (
			cmd *exec.Cmd
			output []byte
			err error
			startTime time.Time
			endTime time.Time
			jobResult *common.JobExecutorResult
			lock *JobLock
		)
		jobResult = &common.JobExecutorResult{}
		startTime = time.Now()
		jobResult.StartTime = startTime
		jobResult.ExecutorInfo = info
		// 抢锁前随机随眠 1000 毫米,保证多个worker进程可以均匀的抢到锁
		time.Sleep(time.Millisecond * time.Duration(rand.Intn(1000)))
		// 获取锁
		lock = InitJobLock(info.Job.JobName,G_EtcdJob.EtcdKv,G_EtcdJob.EtcdLease)
		err = lock.TryLock()
		defer lock.UnLock()
		if err != nil {
			// 上锁失败  失败即结束
			jobResult.EndTime = time.Now()
			jobResult.Err = err
		} else {
			//fmt.Println("开始执行,任务名: " + info.Job.JobName)
			// 重新写入开始时间
			startTime = time.Now()
			jobResult.StartTime = startTime

			// 判断command是否是二进制文件
			if strings.HasPrefix(info.Job.Command,"cm:") {
				// 以cm: 开头的为二进制文件
				commandStr := strings.TrimPrefix(info.Job.Command,"cm:")
				cmd = exec.CommandContext(info.Ctx,commandStr)
			} else {
				// bash执行的命令
				cmd = exec.CommandContext(info.Ctx,"/bin/sh","-c",info.Job.Command)
			}

			// 捕获输出
			output,err = cmd.CombinedOutput()
			endTime = time.Now()
			// 任务执行完成后返回给Scheduler Scheduler将任务从正在执行表中删除
			jobResult.Output = output
			jobResult.Err = err
			jobResult.EndTime = endTime

		}

		// 回传给Scheduler
		G_Scheduler.PushJobResChan(jobResult)
	}()

}

var (
	G_Executor *Executor
)

// 初始化执行器
func InitExecutor() {
	var (
		executor *Executor
	)
	executor = &Executor{}
	G_Executor = executor
}
